import { useEffect, useMemo, useRef } from "react"; // React 基础 API
import { Graph, Shape } from "@antv/x6"; // X6 v2 核心对象（Graph、内置 Edge）
import * as Y from "yjs";
import { Selection } from "@antv/x6-plugin-selection";
import { Keyboard } from "@antv/x6-plugin-keyboard";

// 为节点创建默认的四向端口，便于拖拽连线
const createDefaultPorts = () => ({
  groups: {
    top: {
      position: "top",
      attrs: { circle: { r: 4, magnet: true, stroke: "#5F95FF", strokeWidth: 1, fill: "#fff" } }
    },
    right: {
      position: "right",
      attrs: { circle: { r: 4, magnet: true, stroke: "#5F95FF", strokeWidth: 1, fill: "#fff" } }
    },
    bottom: {
      position: "bottom",
      attrs: { circle: { r: 4, magnet: true, stroke: "#5F95FF", strokeWidth: 1, fill: "#fff" } }
    },
    left: {
      position: "left",
      attrs: { circle: { r: 4, magnet: true, stroke: "#5F95FF", strokeWidth: 1, fill: "#fff" } }
    }
  },
  items: [{ group: "top" }, { group: "right" }, { group: "bottom" }, { group: "left" }]
});

const mapToObject = (m: any) => {
  try {
    if (typeof m?.toJSON === "function") return m.toJSON();
    if (typeof m?.entries === "function") return Object.fromEntries(m.entries());
  } catch {}
  return m;
};

// 数值兜底：将任意值转成 number，非法则返回默认值
const toNumber = (val: any, fallback: number) => {
  const n = Number(val);
  return Number.isFinite(n) ? n : fallback;
};

// 工具：将 JSON 节点写入到 Y.Map
// 传入 节点的数据 然后将 数据映射到 Y.Map 中
const ensureYNode = (yNode: Y.Map<any>, json: any) => {
  yNode.set("id", json.id || crypto.randomUUID()); // 确保 id 存在
  yNode.set("x", json.x ?? 80); // 坐标 x（默认 80）
  yNode.set("y", json.y ?? 80); // 坐标 y（默认 80）
  yNode.set("width", json.width ?? 120); // 宽（默认 120）
  yNode.set("height", json.height ?? 40); // 高（默认 40）
  yNode.set("label", json.label ?? "节点"); // 标签文本（默认“节点”）
  if (!yNode.get("data")) yNode.set("data", new Y.Map()); // 附加数据 data: Y.Map
};

// 工具：将 JSON 边写入到 Y.Map（首次导入或补全字段）
// 传入 变的 数据 然后将 数据映射到 Y.Map 中
const ensureYEdge = (yEdge: Y.Map<any>, json: any) => {
  yEdge.set("id", json.id || crypto.randomUUID()); // 边 id
  yEdge.set("source", json.source); // 源节点 id（必填）
  yEdge.set("target", json.target); // 目标节点 id（必填）
  yEdge.set("label", json.label ?? ""); // 边标签（可空）
  if (!yEdge.get("data")) yEdge.set("data", new Y.Map()); // 附加数据 data: Y.Map
};

// 数据结构
// - flows：`Y.Map<string, Y.Map>`（流程图集合）
// - flow:<blockId>：`Y.Map`（单个流程图命名空间）
//   - `nodes: Y.Array<Y.Map>` 节点数组（每个元素是一个节点 Map）
//   - `edges: Y.Array<Y.Map>` 连线数组（每个元素是一个连线 Map）
//   - `meta:  Y.Map` 画布元信息（缩放、平移、主题等）
// - 节点结构（示例）：`{ id, x, y, width, height, label, data: Y.Map }`
// - 连线结构（示例）：`{ id, source, target, label, data: Y.Map }`

export function FlowchartBlockView({ block, editor }: { block: any; editor: any }) {
  const containerRef = useRef<HTMLDivElement>(null); // 容器 DOM 引用
  const graphRef = useRef<Graph | null>(null); // 保存 Graph 实例
  const initializedRef = useRef(false); // 避免重复初始化

  const yEnv = useMemo(() => {
    const fragment = editor?.options?.collaboration?.fragment as Y.XmlFragment | undefined; // 协同片段
    if (!fragment) return null; // 非协同时返回 null
    const ydoc = (fragment as any).doc as Y.Doc | undefined; // 取出 Y.Doc
    if (!ydoc) return null;

    // flows 总表：放所有流程图块数据
    const flows = ydoc.getMap("flows") as Y.Map<Y.Map<any>>; // Y.Map<string, Y.Map>

    // 当前块的命名空间：flow:<blockId>
    const nsKey = `flow:${block.id}`; // 命名空间 key
    try {
      const flowKeys = Array.from((flows as any).keys?.() ?? []);
      console.log("[flow] yEnv init", { nsKey, flowKeys, blockId: block.id });
    } catch {}
    let yFlow = flows.get(nsKey) as Y.Map<any>; // 读取当前块数据容器
    if (!yFlow) {
      // 若不存在则创建
      yFlow = new Y.Map();
      flows.set(nsKey, yFlow);
    }

    // 保证 nodes/edges/meta 三者存在
    if (!yFlow.get("nodes")) yFlow.set("nodes", new Y.Array<Y.Map<any>>()); // 节点数组
    if (!yFlow.get("edges")) yFlow.set("edges", new Y.Array<Y.Map<any>>()); // 连线数组
    if (!yFlow.get("meta")) yFlow.set("meta", new Y.Map<any>()); // 画布元信息

    return {
      ydoc,
      flows,
      yFlow,
      yNodes: yFlow.get("nodes") as Y.Array<Y.Map<any>>,
      yEdges: yFlow.get("edges") as Y.Array<Y.Map<any>>,
      yMeta: yFlow.get("meta") as Y.Map<any>
    };
  }, [editor, block.id]);

  // 建立索引：id -> Y.Map（节点/边）；id -> X6 Cell（Node/Edge）
  const idToYNode = useRef(new Map<string, Y.Map<any>>()); // 节点 id 映射到对应 Y.Map
  const idToYEdge = useRef(new Map<string, Y.Map<any>>()); // 边 id 映射到对应 Y.Map
  const idToCell = useRef(new Map<string, any>()); // id 映射到 X6 Node/Edge 实例

  // 本地/远端变更标记，防止写入↔回放造成循环
  const isApplyingFromY = useRef(false);

  // 从 Y 节点创建/更新 Graph 节点（Y -> Graph 回放）
  // 将Y 节点 的数据转换成Graph的数据
  const upsertGraphNodeFromY = (graph: Graph, yNode: Y.Map<any>) => {
    const id = String(yNode.get("id")); // 读取 id
    const x = toNumber(yNode.get("x"), 80); // 读取 x（兜底）
    const y = toNumber(yNode.get("y"), 80); // 读取 y（兜底）
    const width = toNumber(yNode.get("width"), 120); // 读取 width（兜底）
    const height = toNumber(yNode.get("height"), 40); // 读取 height（兜底）
    const rawLabel = yNode.get("label");
    const label = rawLabel == null ? "" : String(rawLabel); // 读取 label（兜底）

    let cell = idToCell.current.get(id); // 查是否已有对应 Node

    if (!cell) {
      // 新建节点
      cell = graph.addNode({
        id,
        shape: "rect",
        x,
        y,
        width,
        height,
        label,
        attrs: { body: { stroke: "#333", fill: "#fff" } },
        ports: createDefaultPorts()
      }); // X6 内置矩形节点
      idToCell.current.set(id, cell); // 建立 id -> Node 索引
      idToYNode.current.set(id, yNode); // 建立 id -> YNode 索引
    } else {
      // 已存在：按需更新属性
      cell.position(x, y); // 更新位置
      cell.size(width, height); // 更新尺寸
      cell.setLabel(label); // 更新标签
    }
  };

  // 从 Y 边创建/更新 Graph 边（Y -> Graph 回放）
  // 将Y 边 的数据转换成Graph的数据
  const upsertGraphEdgeFromY = (graph: Graph, yEdge: Y.Map<any>) => {
    const id = String(yEdge.get("id")); // 边 id
    const sourceVal = yEdge.get("source");
    const targetVal = yEdge.get("target");
    if (!sourceVal || !targetVal) return; // 源/目标缺失则跳过渲染该边
    const source = String(sourceVal); // 源 id
    const target = String(targetVal); // 目标 id
    const rawLabel = yEdge.get("label");
    const label = rawLabel == null ? "" : String(rawLabel); // 标签（兜底）

    let cell = idToCell.current.get(id); // 查是否已有 Edge
    if (!cell) {
      // 新建边
      cell = graph.addEdge({ id, source, target, labels: label ? [{ attrs: { label: { text: label } } }] : [] });
      idToCell.current.set(id, cell); // 建立索引
      idToYEdge.current.set(id, yEdge); // 建立索引
    } else {
      // 已存在：更新标签等
      if (label)
        cell.setLabels([{ attrs: { label: { text: label } } }]); // 更新边标签
      else cell.setLabels([]); // 无标签则清空
    }
  };

  // Graph -> Y：新增/更新/删除节点的写入（带事务 + 回环保护）

  //  将 Graph的节点数据 转换成Y的数据
  const writeNodeToY = (yNodes: Y.Array<Y.Map<any>>, nodeCell: any, kind: "add" | "update" | "remove") => {
    if (!yEnv) return; // 非协同直接返回
    if (isApplyingFromY.current) return; // 正在回放远端变更时不反写
    const { ydoc } = yEnv; // 取出 doc 用于事务
    const id = String(nodeCell.id); // X6 节点 id

    console.log("[flow] writeNodeToY enter", { kind, id, isApplyingFromY: isApplyingFromY.current });
    Y.transact(ydoc, () => {
      // 开启 Y 事务（可撤销、合并）
      if (kind === "remove") {
        // 删除节点
        const idx = yNodes.toArray().findIndex(n => String(n.get("id")) === id); // 找到数组索引
        if (idx >= 0) {
          yNodes.delete(idx, 1); // 从 Y 数组删除
          console.log("[flow] writeNodeToY remove", { id, idx });
        }
        idToCell.current.delete(id); // 清理本地映射
        idToYNode.current.delete(id); // 清理本地映射
        return; // 结束
      }

      // 新增或更新
      let yNode = idToYNode.current.get(id); // 是否已有对应 Y.Map
      if (!yNode) {
        // 新增
        yNode = new Y.Map<any>(); // 创建 Y 节点
        ensureYNode(yNode, {
          // 补全必需字段
          id,
          x: nodeCell.position().x, // 读取 X6 节点位置 x
          y: nodeCell.position().y, // 读取 X6 节点位置 y
          width: nodeCell.size().width, // 宽
          height: nodeCell.size().height, // 高
          label: String(nodeCell.getLabel() ?? "") // 标签
        });
        yNodes.push([yNode]); // 追加到 Y 数组（原子变更）
        idToYNode.current.set(id, yNode); // 建立索引
        console.log("[flow] writeNodeToY add", mapToObject(yNode));
      } else {
        // 更新
        const nx = nodeCell.position().x;
        const ny = nodeCell.position().y;
        const nw = nodeCell.size().width;
        const nh = nodeCell.size().height;
        const nl = String(nodeCell.getLabel() ?? "");
        yNode.set("x", nx); // 回写 x
        yNode.set("y", ny); // 回写 y
        yNode.set("width", nw); // 回写 width
        yNode.set("height", nh); // 回写 height
        yNode.set("label", nl); // 回写 label
        console.log("[flow] writeNodeToY update", { id, nx, ny, nw, nh, nl });
      }
    });
  };

  // Graph -> Y：新增/更新/删除边的写入
  //  将 Graph的边数据 转换成Y的数据
  const writeEdgeToY = (yEdges: Y.Array<Y.Map<any>>, edgeCell: any, kind: "add" | "update" | "remove") => {
    if (!yEnv) return; // 非协同返回
    if (isApplyingFromY.current) return; // 回放中不反写
    const { ydoc } = yEnv; // 取 doc
    const id = String(edgeCell.id); // 边 id

    console.log("[flow] writeEdgeToY enter", { kind, id, isApplyingFromY: isApplyingFromY.current });
    Y.transact(ydoc, () => {
      // 事务
      if (kind === "remove") {
        // 删除边
        const idx = yEdges.toArray().findIndex(e => String(e.get("id")) === id); // 定位索引
        if (idx >= 0) {
          yEdges.delete(idx, 1); // 从 Y 删除
          console.log("[flow] writeEdgeToY remove", { id, idx });
        }
        idToCell.current.delete(id); // 清理映射
        idToYEdge.current.delete(id);
        return;
      }

      // 新增或更新
      let yEdge = idToYEdge.current.get(id); // 查是否已有 Y 边
      const src = edgeCell.getSourceCellId?.(); // 源节点 id（X6 API）
      const tgt = edgeCell.getTargetCellId?.(); // 目标节点 id（X6 API）
      const label = String(edgeCell.getLabels?.()[0]?.attrs?.label?.text ?? ""); // 读取标签

      if (!yEdge) {
        // 新增
        yEdge = new Y.Map<any>(); // 创建 Y.Map
        ensureYEdge(yEdge, { id, source: src, target: tgt, label }); // 补全字段
        yEdges.push([yEdge]); // 追加到数组
        idToYEdge.current.set(id, yEdge); // 索引
        console.log("[flow] writeEdgeToY add", mapToObject(yEdge));
      } else {
        // 更新
        yEdge.set("source", src); // 回写 source
        yEdge.set("target", tgt); // 回写 target
        yEdge.set("label", label); // 回写 label
        console.log("[flow] writeEdgeToY update", { id, src, tgt, label });
      }
    });
  };

  useEffect(() => {
    if (!yEnv || !containerRef.current) return; // 依赖协同上下文与容器
    if (initializedRef.current) return; // 已初始化则跳过
    initializedRef.current = true;

    // 1) 初始化 X6 Graph（画布/网格/平移缩放/连线路由等）
    // 重置本地索引，避免复用上一次 Graph 的 cell 导致新 Graph 为空
    idToCell.current = new Map();
    idToYNode.current = new Map();
    idToYEdge.current = new Map();

    const graph = new Graph({
      container: containerRef.current, // 绑定容器
      grid: { size: 10, visible: true }, // 网格 10px、可见
      panning: true, // 允许平移
      mousewheel: { enabled: true, modifiers: "ctrl" }, // Ctrl+滚轮缩放

      connecting: {
        // 连线配置
        allowBlank: false, // 禁止连到空白
        allowLoop: false, // 禁止自连
        snap: true, // 吸附端口
        router: "manhattan", // 直角路由
        connector: "rounded", // 圆角连接器
        createEdge() {
          // 自定义默认边样式
          return new Shape.Edge({ attrs: { line: { stroke: "#5F95FF", strokeWidth: 2 } } });
        }
      }
    });

    //     @antv/x6-plugin-selection：给图启用“选择能力”。支持节点/边的点击选中、多选、框选、显示选中框，以及相关 API（如 graph.getSelectedCells）。构造器里不再写 selecting，而是 graph.use(new Selection({...}))。

    // @antv/x6-plugin-keyboard：给图启用“键盘快捷键能力”。提供 graph.bindKey/unbindKey，用来绑定 Delete/Backspace 删除、以及自定义快捷键（如 Ctrl/Cmd+Z 等）。
    graph.use(new Selection({ enabled: true, multiple: true, rubberband: true, showNodeSelectionBox: true }));
    graph.use(new Keyboard({ enabled: true }));
    console.log("[flow] graph created", { container: !!containerRef.current });

    graphRef.current = graph; // 保存实例

    // 2) 将 Y 中已有数据回放到 Graph（初始渲染）
    if (yEnv) {
      isApplyingFromY.current = true; // 标记：开始回放，防回写
      const { yNodes, yEdges } = yEnv; // 取节点/边数组
      const nodesArr = yNodes.toArray();
      const edgesArr = yEdges.toArray();
      console.log("[flow] init nodes", nodesArr.map(mapToObject));
      console.log("[flow] init edges", edgesArr.map(mapToObject));
      // 将所有节点的数据 一次应用graph 示例
      nodesArr.forEach(yNode => upsertGraphNodeFromY(graph, yNode)); // 回放所有节点

      edgesArr.forEach(yEdge => upsertGraphEdgeFromY(graph, yEdge)); // 回放所有边
      isApplyingFromY.current = false; // 回放结束
      (graph as any).centerContent?.(); // 居中以确保可见
      console.log("[flow] graph after init", {
        nodeCount: (graph as any).getNodes?.()?.length,
        edgeCount: (graph as any).getEdges?.()?.length
      });
    }

    // 2.5) 双击空白处新增一个默认节点
    graph.on("blank:dblclick", ({ x, y }) => {
      graph.addNode({
        x: x - 60,
        y: y - 20,
        width: 120,
        height: 40,
        label: "节点",
        attrs: { body: { stroke: "#333", fill: "#fff" } },
        ports: createDefaultPorts()
      });
      // 写入由 node:added 事件统一处理
      console.log("[flow] blank:dblclick add node", { x, y });
    });

    // 2.6) 删除键：删除选中节点/边
    (graph as any).bindKey?.(["backspace", "delete"], () => {
      const cells = (graph as any).getSelectedCells?.() ?? [];
      if (cells.length) graph.removeCells(cells);
      console.log("[flow] delete key", { removed: cells.length });
      return false;
    });

    // 绑定 本地的操作 事件，将操作事件对应的数据变化 转换成 事件对应的数据变化
    // 3) 绑定 Graph -> Y 的写入事件（节点）
    graph.on("node:added", ({ node }) => {
      console.log("[flow] graph node:added", node?.id);
      yEnv && writeNodeToY(yEnv.yNodes, node, "add");
    }); // 新增节点
    graph.on("node:removed", ({ node }) => {
      console.log("[flow] graph node:removed", node?.id);
      yEnv && writeNodeToY(yEnv.yNodes, node, "remove");
    }); // 删除节点
    graph.on("node:change:position", ({ node }) => {
      console.log("[flow] graph node:change:position", node?.id);
      yEnv && writeNodeToY(yEnv.yNodes, node, "update");
    }); // 移动节点
    graph.on("node:change:size", ({ node }) => {
      console.log("[flow] graph node:change:size", node?.id);
      yEnv && writeNodeToY(yEnv.yNodes, node, "update");
    }); // 调整尺寸
    graph.on("node:change:attrs", ({ node }) => {
      console.log("[flow] graph node:change:attrs", node?.id);
      yEnv && writeNodeToY(yEnv.yNodes, node, "update");
    }); // 更新标签等

    // 4) 绑定 Graph -> Y 的写入事件（边）
    graph.on("edge:added", ({ edge }) => {
      console.log("[flow] graph edge:added", edge?.id);
      yEnv && writeEdgeToY(yEnv.yEdges, edge, "add");
    }); // 新增边
    graph.on("edge:removed", ({ edge }) => {
      console.log("[flow] graph edge:removed", edge?.id);
      yEnv && writeEdgeToY(yEnv.yEdges, edge, "remove");
    }); // 删除边
    graph.on("edge:connected", ({ edge }) => {
      console.log("[flow] graph edge:connected", edge?.id);
      yEnv && writeEdgeToY(yEnv.yEdges, edge, "update");
    }); // 连接端口
    graph.on("edge:change:labels", ({ edge }) => {
      console.log("[flow] graph edge:change:labels", edge?.id);
      yEnv && writeEdgeToY(yEnv.yEdges, edge, "update");
    }); // 修改标签

    // 5) Y -> Graph 的监听与回放（增删改最小化同步）
    const disposers: Array<() => void> = []; // 统一收集取消函数

    if (yEnv) {
      const { yNodes, yEdges } = yEnv; // 取数组引用
      const { yFlow } = yEnv as any;

      // 5.1 监听 nodes 数组的结构变化（插入/删除） 这里主要就是 监听远程 发来的变化 然后 同步 本地ui
      const onNodes = (evt: Y.YArrayEvent<Y.Map<any>>) => {
        isApplyingFromY.current = true; // 标记回放中
        evt.changes.delta.forEach(d => {
          // 遍历变更块

          if (d.insert) {
            // 将 新插入的 yNode 数据 同步到 graph 中
            (d.insert as Y.Map<any>[]).forEach(yNode => {
              upsertGraphNodeFromY(graph, yNode); // 回放新增节点
              // 为新节点挂字段监听
              attachNodeObserver(yNode);
            });
          }

          if (d.delete) {
            // 删除数量
            // 删除需要根据前镜像判断，简化处理：全量对齐（小规模数据场景可接受）
            const currentIds = new Set(yNodes.toArray().map(n => String(n.get("id")))); // Y 当前 id 集

            // 移除 Graph 中已不存在的节点
            Array.from(idToCell.current.entries()).forEach(([id, cell]) => {
              if (cell.isNode?.() && !currentIds.has(id)) {
                // Graph 有但 Y 没有
                cell.remove(); // 从 Graph 删除
                idToCell.current.delete(id); // 清索引
                idToYNode.current.delete(id);
              }
            });
          }
        });
        isApplyingFromY.current = false; // 回放结束
        console.log("[flow] yNodes delta", evt.changes.delta);
        console.log("[flow] graph after nodes delta", {
          nodeCount: (graph as any).getNodes?.()?.length,
          edgeCount: (graph as any).getEdges?.()?.length
        });
      };

      yNodes.observe(onNodes); // 订阅 nodes 结构变更 监听 整个数组的变化

      disposers.push(() => yNodes.unobserve(onNodes)); // 记录取消函数

      // 5.2 为每个 yNode 单独监听字段变化（x/y/size/label 等）
      const attachNodeObserver = (yNode: Y.Map<any>) => {
        const onFields = (e?: any) => {
          // 字段变更回放
          isApplyingFromY.current = true; // 标记回放
          upsertGraphNodeFromY(graph, yNode); // 最小化更新该节点
          isApplyingFromY.current = false; // 回放结束
          try {
            console.log("[flow] yNode fields changed", mapToObject(yNode), e);
          } catch {}
        };
        (yNode as any).observe(onFields); // 订阅
        disposers.push(() => (yNode as any).unobserve(onFields)); // 记录取消
      };

      yNodes.toArray().forEach(n => attachNodeObserver(n)); // 现有节点全部挂监听 监听数组里面 单个节点的变化

      // 5.3 监听 edges 数组的结构变化（插入/删除）
      const onEdges = (evt: Y.YArrayEvent<Y.Map<any>>) => {
        isApplyingFromY.current = true; // 标记回放
        evt.changes.delta.forEach(d => {
          if (d.insert) {
            // 新增的边们
            (d.insert as Y.Map<any>[]).forEach(yEdge => {
              upsertGraphEdgeFromY(graph, yEdge); // 回放新增边
              attachEdgeObserver(yEdge);
            });
          }
          if (d.delete) {
            // 删除数量
            const currentIds = new Set(yEdges.toArray().map(e => String(e.get("id")))); // Y 当前边 id 集
            Array.from(idToCell.current.entries()).forEach(([id, cell]) => {
              if (cell.isEdge?.() && !currentIds.has(id)) {
                // Graph 有但 Y 没有
                cell.remove(); // 删除边
                idToCell.current.delete(id); // 清索引
                idToYEdge.current.delete(id);
              }
            });
          }
        });
        isApplyingFromY.current = false; // 回放结束
        console.log("[flow] yEdges delta", evt.changes.delta);
        console.log("[flow] graph after edges delta", {
          nodeCount: (graph as any).getNodes?.()?.length,
          edgeCount: (graph as any).getEdges?.()?.length
        });
      };

      yEdges.observe(onEdges); // 订阅边数组

      disposers.push(() => yEdges.unobserve(onEdges)); // 记录取消

      // 5.4 为每条 yEdge 单独监听字段变化（source/target/label）
      const attachEdgeObserver = (yEdge: Y.Map<any>) => {
        const onFields = (e?: any) => {
          isApplyingFromY.current = true; // 标记回放
          upsertGraphEdgeFromY(graph, yEdge); // 最小化更新该边
          isApplyingFromY.current = false; // 回放结束
          try {
            console.log("[flow] yEdge fields changed", mapToObject(yEdge), e);
          } catch {}
        };
        (yEdge as any).observe(onFields); // 订阅
        disposers.push(() => (yEdge as any).unobserve(onFields)); // 记录取消
      };

      yEdges.toArray().forEach(e => attachEdgeObserver(e)); // 现有边全部挂监听

      // 5.5 兜底：深度监听 yFlow 的任意变更（防止某些变更未被以上监听捕获）
      const reconcileFromY = () => {
        console.log("[flow] observeDeep -> reconcile");
        isApplyingFromY.current = true;
        try {
          const currentNodeIds = new Set<string>();
          yNodes.toArray().forEach((n: any) => {
            upsertGraphNodeFromY(graph, n);
            currentNodeIds.add(String(n.get("id")));
          });
          // 删除孤儿节点
          Array.from(idToCell.current.entries()).forEach(([id, cell]) => {
            if (cell.isNode?.() && !currentNodeIds.has(id)) {
              cell.remove();
              idToCell.current.delete(id);
              idToYNode.current.delete(id);
            }
          });

          const currentEdgeIds = new Set<string>();
          yEdges.toArray().forEach((e: any) => {
            upsertGraphEdgeFromY(graph, e);
            currentEdgeIds.add(String(e.get("id")));
          });
          // 删除孤儿边
          Array.from(idToCell.current.entries()).forEach(([id, cell]) => {
            if (cell.isEdge?.() && !currentEdgeIds.has(id)) {
              cell.remove();
              idToCell.current.delete(id);
              idToYEdge.current.delete(id);
            }
          });
        } finally {
          isApplyingFromY.current = false;
          console.log("[flow] reconcile done", {
            nodeCount: (graph as any).getNodes?.()?.length,
            edgeCount: (graph as any).getEdges?.()?.length
          });
        }
      };
      (yFlow as any).observeDeep?.(reconcileFromY);
      disposers.push(() => (yFlow as any).unobserveDeep?.(reconcileFromY));
    }

    // 6) 清理：卸载组件时移除监听与释放 Graph
    return () => {
      // 先卸载所有 Y 监听，避免多次挂载导致重复回放/跨实例操作
      try {
        // 一定要先移除y的监听
        // 你在 effect 清理时没有先解除 Y 的监听，导致下次挂载时老监听还在，两个 Graph 实例交替改同一份 idToCell 或直接 remove 了对方的 cell。
        disposers.forEach(d => d());
      } catch {}
      graph.dispose(); // 释放 X6 实例
      graphRef.current = null; // 置空引用
      // 清理索引，确保下次挂载时不会复用旧 cell
      idToCell.current.clear();
      idToYNode.current.clear();
      idToYEdge.current.clear();
      initializedRef.current = false; // 允许下次条件满足时重新初始化
    };
  }, [yEnv, containerRef.current]);

  console.log("yEnv", yEnv);

  return (
    <div
      ref={containerRef}
      contentEditable={false}
      tabIndex={0}
      style={{ width: block.props.width, height: block.props.height, minHeight: 200 }}
    />
  );
}
